package com.javaex.book.web;

import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.javaex.book.annotation.Controller;
import com.javaex.book.annotation.RequestMapping;
import com.javaex.book.utils.ClassFileUtils;
import com.javaex.book.utils.LoggerUtils;

public class HandlerMapping {
	
	private static final Logger logger = LoggerFactory.getLogger(HandlerMapping.class);
	
	/** 存放Controller类文件的包（文件夹）名 */
	private static final String CONTROLLER_PACKAGE_NAME = "controller";
	
	/** 存放请求路径对应的处理Handler，一个Controller中的Method方法对应一个Handler */
	private static Map<String, Handler> handlerMap = new ConcurrentHashMap<>();
	
	static {
		// 读取Controller类文件，确定请求路径与Controller的映射关系
		determineUrlsForHandler();
		logger.debug(LoggerUtils.mapToString(handlerMap));
	}
	
	/**
	 * 根据请求uri和请求类型获取对象的handler
	 * @param uri 请求uri
	 * @param method 请求类型
	 * @return 处理当前请求的Handler
	 */
	public Handler getHandler(String uri, String method) {
		return handlerMap.get(method.toUpperCase() + " " + uri);
	}
	
	/**
	 * 确定请求路径与Controller文件、文件中的方法的映射关系
	 */
	private static void determineUrlsForHandler() {
		// 获取所有Controller类实例
		List<Class<?>> controllerList = ClassFileUtils.getClassList(CONTROLLER_PACKAGE_NAME);
		for (Class<?> clazz : controllerList) {
			// 获取类上标注的@Controller注解
			Controller controller = clazz.getDeclaredAnnotation(Controller.class);
			// 如果@Controller注解不存在，则忽略这个类
			if (controller == null) {
				continue;
			}
			// 创建当前类的实例
			Object instance = null;
			try {
				instance = clazz.getDeclaredConstructor().newInstance();
			} catch (Exception e) {
				logger.error("{}类实例创建失败", clazz.getSimpleName());
				continue;
			} 
			
			// 获取当前Controller类中所有的方法
			Method[] methods = clazz.getDeclaredMethods();
			for (Method method : methods) {
				// 获取方法上的 @RequestMapping 注解
				RequestMapping requestMapping = method.getDeclaredAnnotation(RequestMapping.class);
				// 如果方法上没有该注解，则忽略此方法
				if (requestMapping == null) {
					continue;
				}
				// 创建 Handler，并赋值
				Handler handler = new Handler(method, controller.value() + requestMapping.value(), requestMapping.method(), instance);
				handlerMap.put(handler.getRequestMethod().toString().toUpperCase() + " " + handler.getUrlPattern(), handler);
			}
		}
	}
}